package com.phoenix.jsef.common;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;

import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 该类为通用工具类
 * @author 李启联
 *
 */
public class CUtils {

	/*************************生成唯一ID******************************/
    public enum IdType
    {
        intType,
        stringType;
    }
    private static int rep = 0;
   
    public static String newId(IdType idtype, int len)
    {
    	String str = "";

        if (idtype == IdType.stringType)
        {
        	str = CUtils.createRandomCharData(len).toUpperCase();
        }
        else if (idtype == IdType.intType)
        {
        	str = CUtils.createData(len);
        }
        return str;
    }
    
    private static String str[]={"0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"
            ,"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
    
    public static String getId(int len){
        Random e = new Random();
        int n=0;
        String id="";
        for(int i=0;i<len;i++){
            n=e.nextInt(str.length-1);
            id+=str[n];
        }
        return id;
    }
    
    //根据指定长度生成字母和数字的随机数
    //0~9的ASCII为48~57
    //A~Z的ASCII为65~90
    //a~z的ASCII为97~122
    public static String createRandomCharData(int length)
    {
        StringBuilder sb=new StringBuilder();
        Random rand=new Random();//随机用以下三个随机生成器
        Random randdata=new Random();
        int data=0;
        for(int i=0;i<length;i++)
        {
            int index=rand.nextInt(3);
            //目的是随机选择生成数字，大小写字母
            switch(index)
            {
            case 0:
                 data=randdata.nextInt(10);//仅仅会生成0~9
                 sb.append(data);
                break;
            case 1:
                data=randdata.nextInt(26)+65;//保证只会产生65~90之间的整数
                sb.append((char)data);
                break;
            case 2:
                data=randdata.nextInt(26)+97;//保证只会产生97~122之间的整数
                sb.append((char)data);
                break;
            }
        }
        
        return sb.toString();
    }
                       
    //根据指定长度生成纯数字的随机数
    public static String createData(int length) {
        StringBuilder sb=new StringBuilder();
        Random rand=new Random();
        for(int i=0;i<length;i++)
        {
            sb.append(rand.nextInt(10));
        }
        
        return sb.toString();
    }
    
    //生成随机数字和字母,  
    public static String getStringRandom(int length) {  
          
        String val = "";  
        Random random = new Random();  
          
        //参数length，表示生成几位随机数  
        for(int i = 0; i < length; i++) {  
              
            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";  
            //输出字母还是数字  
            if( "char".equalsIgnoreCase(charOrNum) ) {  
                //输出是大写字母还是小写字母  
                int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;  
                val += (char)(random.nextInt(26) + temp);  
            } else if( "num".equalsIgnoreCase(charOrNum) ) {  
                val += String.valueOf(random.nextInt(10));  
            }  
        }  
        return val;  
    }
    
    /*************************驼峰命名与下划线命名的转换******************************/
    public static final char UNDERLINE = '_';
    /**
     * 驼峰格式字符串转换为下划线格式字符串
     * eg: helloWord >> hello_word; HelloWord >> _hello_word;
     * @param param
     * @return
     */
    public static String camelToUnderline(String param) {
    	return camelToUnderline(param,true);
    }
    
    /**
     * 驼峰格式字符串转换为下划线格式字符串 <br/>
     * eg: helloWord >> hello_word ; 【HelloWord >> _hello_word 如果 ignoreFirstChar 为 true 则：HelloWord >> hello_word 】;
     * 在C#语言中的命名中很多情况第一个字符为大写 如：属性的定义
     * @param param 需要转换的字符串
     * @param ignoreFirstChar 是否忽略第一个字符为大写的情况(在C#语言中的命名中很多情况第一个字符为大写[大驼峰] 如：属性的定义)
     * @return
     */
    public static String camelToUnderline(String param, boolean ignoreFirstChar) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);        
            if (Character.isUpperCase(c)) {
            	if(i == 0 && ignoreFirstChar) {//忽略第一个字母为大写的情况 		
            	}
            	else
            		sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 下划线格式字符串转换为驼峰格式字符串
     * eg:hello_word >> helloWord ; HELLO_word >> HELLOWord
     * @param param
     * @return
     */
    public static String underlineToCamel(String param) {
    	return underlineToCamel(param,false);
    }
    
    /**
     * 下划线格式字符串转换为驼峰格式字符串<br/>
     * eg:hello_word >> helloWord 如果 tranForFirstCharToUpCase 为tru 则 hello_word >> HelloWord ; HELLO_word >> HELLOWord
     * @param param 需要转换的字符串
     * @param tranForFirstCharToUpCase 是否把转换后的驼峰名称的第一个字符为大写
     * @return
     */
    public static String underlineToCamel(String param,boolean tranForFirstCharToUpCase) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (c == UNDERLINE) {
                if (++i < len) {
                    sb.append(Character.toUpperCase(param.charAt(i)));
                }
            } else {
            	if(i == 0 && tranForFirstCharToUpCase)
            		 sb.append(Character.toUpperCase(c));
            	else
            		sb.append(c);
            }
        }
        return sb.toString();
    }

    /**
     * 下划线格式字符串转换为驼峰格式字符串2
     * hello_word (大小写无关) >> HelloWord ; HELLO_word >> HELLOWord
     * @param param
     * @return
     */
    public static String underlineToCamel2(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        StringBuilder sb = new StringBuilder(param);
        Matcher mc = Pattern.compile("_").matcher(param);
        int i = 0;
        while (mc.find()) {
            int position = mc.end() - (i++);
            sb.replace(position - 1, position + 1, sb.substring(position, position + 1).toUpperCase());
        }
        return sb.toString();
    }
    
    /**
     * 将首字母转小写
     * @param s 源字符串
     * @return
     */
    public static String toLowerCaseFirstOne(String s){
      if(Character.isLowerCase(s.charAt(0)))
        return s;
      else
        return (new StringBuilder()).append(Character.toLowerCase(s.charAt(0))).append(s.substring(1)).toString();
    }

    /**
     * 将首字母转大写
     * @param s 源字符串
     * @return
     */
    public static String toUpperCaseFirstOne(String s){
      if(Character.isUpperCase(s.charAt(0)))
        return s;
      else
        return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
    }
    
    /**
     * 判断类型为 Map<String,Object> 形式的Map 是否包含不区分大小写指定的key
     * @param map 待判断的Map对象
     * @param compareKey 指定要比较键的名称 
     * @return
     */
    public static boolean mapContainsKeyIgnoreCase(Map<String,Object> map,String compareKey){
    	boolean isContainsKey =false;  	
    	for(String key : map.keySet()){
    		if (key.equalsIgnoreCase(compareKey)){
    			isContainsKey = true;
    			break;
    		}
    	}   	
    	return isContainsKey;
    }

    /**
     * 判断类型为 Map<String,Object> 形式的Map 是否包含与指定待比较(1.不分大小写 2.驼峰格式相互可以转成)的key
     * @param map 待判断的Map对象
     * @param compareKey 指定要比较键的名称
     * @return
     */
    public static boolean mapContainsLikeKey(Map<String,Object> map,String compareKey){
        boolean isContainsKey =false;
        for(String key : map.keySet()){
            if(compareKey.equalsIgnoreCase(key) || compareKey.equalsIgnoreCase(underlineToCamel(key))){
                isContainsKey = true;
                break;
            }
        }
        return isContainsKey;
    }
    
	/**
	 * 从Map中得到指定名称的键 不区分大小写
	 * @param map 型为 Map<String,Object> 形式的Map
	 * @param targetKey 指定要得到目标键的名称
	 * @return Map中实际设置的键
	 */
	public static String getMapKeyIgnoreCase(Map<String, Object> map, String targetKey) {
		String resultKey = "";
		if (!targetKey.isEmpty() || !targetKey.equals("")) {
			for (String key : map.keySet()) {
				if (key.equalsIgnoreCase(targetKey)) {
					resultKey = key;
					break;
				}
			}
		}
		return resultKey;
	}
	
	/**
	 * 从Map中得到指定名称(不区分大小写)键 对应的值
	 * @param map 型为 Map<String,Object> 形式的Map
	 * @param targetKey 指定要得到目标键的名称
	 * @return Map中实际键对应的值
	 */
	public static Object getMapValueByKeyIgnoreCase(Map<String, Object> map, String targetKey) {
		Object resultValue = null;	
		String key = "";
		key = getMapKeyIgnoreCase(map,targetKey);
		if(key.length() > 0) {
			resultValue = map.get(key);	
		}		
		return resultValue;
	}
	
	/**
	 * 根据模糊的键名称找到Map中对应的值
	 * 1.不分大小写 
	 * 2.驼峰格式相互可以转成
	 * 符合这两点去匹配
	 * @param likeKey
	 * @param map
	 * @return
	 */
	public static Object getValueFromMapByLikeKey(String likeKey,Map<String, Object> map) {
		String mapKey = "";
		Object mapValue = null;
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			if(likeKey.equalsIgnoreCase(entry.getKey()) || likeKey.equalsIgnoreCase(underlineToCamel(entry.getKey()))){
				mapValue = entry.getValue();
				break;
			}
		}	
		return mapValue;
	}
	
	/**
	 * 过滤Map形式的List数组
	 * 类似与.Net平台中对Table(表)的(Table.Select("columnName = "value" "))过滤 返回 DataRow[]
	 * @param sourceList 要过滤的Map形式的List数组(源)
	 * @param keyName	 map中的键名称
	 * @param keyValue   map中的键名称对于的值
	 * @return
	 */
	public static List<Map<String,Object>> filterMapListByKey(List<Map<String,Object>> sourceList,String keyName,Object keyValue){		
		List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
		for (Map<String, Object> row : sourceList) {
			keyName = getMapKeyIgnoreCase(row,keyName);//从Map中得到指定名称的键 不区分大小写,这样可用性较高
			if(row.containsKey(keyName) && keyValue.equals(row.get(keyName) == null ? "" : row.get(keyName)) ) {
				list.add(row);
			}
		}		
		return list;
	}
	
	/**
	 * 把String文本内容保存到指定的文件
	 * @param pathName 文件路径
	 * @param strBuffer 文本内容
	 */
    public static void textSaveToFile(String pathName, String strBuffer) {  
	    try  
	    {      
	      File fileText = new File(pathName);  
	      FileWriter fileWriter = new FileWriter(fileText);  
	  
	      fileWriter.write(strBuffer);  
	      fileWriter.close();  
	    }  
	    catch (IOException e)  
	    {  
	      e.printStackTrace();  
	    }  
	}
    
    /**
     * 把文件以字符串的形式输出
     * @param file 加载的文件
     * @return 文本内容
     *  例:
     *  	File file = new File("D:/errlog.txt");
     *  	System.out.println(loadFileToString(file));
     */
    public static String loadFileToString(File file){
        StringBuilder result = new StringBuilder();
        try{
            BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
            String s = null;
            while((s = br.readLine())!=null){//使用readLine方法，一次读一行
                result.append(s+System.lineSeparator());
            }
            br.close();    
        }catch(Exception e){
            e.printStackTrace();
        }
        return result.toString();
    }
    
    public static String loadClassPathResourceFileToString(String resourceFilePath) throws IOException {
        Resource resource = new ClassPathResource(resourceFilePath.replace("classpath:",""));
        File file = resource.getFile();
        return loadFileToString(file);
    }

    /**
     *
     * @param resourceFilePath
     * @return
     * @throws IOException
     */
    public static File loadClassPathResourceFile(String resourceFilePath)throws IOException {
        Resource resource = new ClassPathResource(resourceFilePath.replace("classpath:",""));
        File file = resource.getFile();
        return file;
    }


    /**
     * 对List集合分页取数实现
     * @param pageIndex 页码
     * @param pageSize  每页条数
     * @param list      要分页的原始集合
     * @return  分页后取得的集合
     * @throws Exception
     */
    public static List<Object> getPagedList(int pageIndex, int pageSize, List<Map<String, Object>> list)throws Exception {
        List<Object> result = new ArrayList<Object>();
        if (list != null && list.size() > 0) {
            int allCount = list.size();
            if(pageSize > allCount)
                pageSize = allCount;

            int pageCount = (allCount + pageSize - 1) / pageSize;
            if (pageIndex >= pageCount) {
                pageIndex = pageCount;
            }
            int start = (pageIndex - 1) * pageSize;
            int end = pageIndex * pageSize;
            if (end >= allCount) {
                end = allCount;
            }
            for (int i = start; i < end; i++) {
                result.add(list.get(i));
            }
        }
        return (result != null && result.size() > 0) ? result : null;
    }

    /**
     * 得到当前正在执行的方法的方法名称
     * @return 方法名称
     */
    public static String getExecutingMethodName() {
        StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stackTrace[2];
        return e.getMethodName();
    }

    /**
     * 判断一个Class是否是Collection类型
     * @param c
     * @return
     */
    public static boolean isCollection(Class c){
        return Collection.class.isAssignableFrom(c);
    }

}
